//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
    g_AverageFPS.MarkFrame();
    if (!g_bInAutoTesting && g_AverageFPS.GetElapsedTime() > 5)
        g_AverageFPS.Reset();
    float fFPS = g_AverageFPS.GetAverageFPS();
    
    float fMeasuredCPUActivePerDraw = MeasureCPUActive();
    g_dwACPULoadPosition = (g_dwACPULoadPosition + 1) % g_dwNumberArtificialCPULoadSamples;
    g_fArtificialCPULoad[g_dwACPULoadPosition] = fMeasuredCPUActivePerDraw;
    if(g_bInAutoTesting || fFPS >3.0f)
        g_fArtificialCPULoadPerFrame = AverageArtificialCPULoadSamples();
    else
        g_fArtificialCPULoadPerFrame = fMeasuredCPUActivePerDraw;



    g_bCheckDrawTime = true;
    g_dwCPUPosition = ( g_dwCPUPosition + 1 ) % g_dwNumberCPUSamples;
    g_fCPU[g_dwCPUPosition] = g_fDrawCost;
    if(g_bInAutoTesting || fFPS >3.0f)
        g_fMeasuredTotalCPULoadPerDraw = AverageCPUSamples();
    else
        g_fMeasuredTotalCPULoadPerDraw = g_fDrawCost;


    WCHAR wszOutput[1024];
    if(g_bMultiThread)
    {
        StringCchPrintf( wszOutput, 1024, L"%s FPS %.2f with %d threads with %s.", 
            (g_SampleStablizationState == SAMPLE_STABALIZATION_STEP3_RECORD) ? L"  MEASURING" : L"Stabilizing",
            fFPS, 
            g_dwNumberofRecordThreads+1,
            g_bAllowRecordToOverlapPlayback ? L"Playback Overlap" : L"No Playback Overlap" );
    }
    else
    {
        StringCchPrintf( wszOutput, 1024, L"%s FPS %.2f ", 
            (g_SampleStablizationState == SAMPLE_STABALIZATION_STEP3_RECORD) ? L"  MEASURING" : L"Stabilizing",
            fFPS);
    }

    g_UI.GetStatic( IDC_OUTPUT )->SetText(wszOutput );
    if(g_bInAutoTesting)
        StringCchPrintf( wszOutput, 1024, L"Testing Loops = %d, DP goal = %d, Threads = %d config. Last Measured FPS = %.3f\n Measured cpu load per draw call: %.1f microseconds. %.1f microseconds generated from %d loops", g_TestLoops , g_TestDPs , g_TestThreads , g_fMeasuredFPS , g_fMeasuredTotalCPULoadPerDraw,g_fArtificialCPULoadPerFrame,g_dwCPULoops);
    else
        StringCchPrintf( wszOutput, 1024, L"Measured cpu load per draw call: %.1f microseconds. %.1f microseconds generated from %d loops", g_fMeasuredTotalCPULoadPerDraw,g_fArtificialCPULoadPerFrame,g_dwCPULoops);
    g_UI.GetStatic( IDC_LABELMEASUREDCPU )->SetText(wszOutput );
    
    if( g_bAutoTesting  && g_bStopTesting)
    {
        g_bAutoTesting = false;
        g_bInAutoTesting = false;
        g_bSaveSample = false; 
        if(g_pOutputFile)
            fclose(g_pOutputFile);
        g_pOutputFile = NULL;
        ShowSliders(true);
        g_HUD.GetButton( IDC_STARTTESTING )->SetText( L"Start Testing");
    }
    if((g_bSaveSample || g_bAutoTesting) && !g_bInAutoTesting && g_pOutputFile==NULL) 
    {
        ShowSliders(false);
        OpenDataFile("c:\\testresults.txt");
        if(g_bSaveSample)
        {
            g_TestStartLoops=g_dwCPULoops;
            g_TestEndLoops=g_dwCPULoops;
            g_TestLoopsIncrement = 10;

            g_TestStartDPs=g_dwNumberofObjectsSqrt;
            g_TestEndDPs=g_dwNumberofObjectsSqrt;
            g_TestDPsIncrement = 10;

            g_TestStartThreads=g_dwNumberofRecordThreads;
            g_TestEndThreads=g_dwNumberofRecordThreads;
            g_TestThreadsIncrement = 10;
            g_bAutoTesting = true;
            g_bSaveSample = false;
        }
        else
        {
            OutputHeader(g_pOutputFile);
            SetState(g_TestStartLoops,g_TestStartDPs,g_TestStartThreads);
        }
        g_SampleStablizationState = SAMPLE_STABALIZATION_STEP1_RESET;
        QueryPerformanceCounter( &g_TestStartTime );
        g_bInAutoTesting = true;
    }
    if(g_bAutoTesting && g_bInAutoTesting && g_pOutputFile)
    {
        ShowSliders(false);

        LARGE_INTEGER currentTime;
        QueryPerformanceCounter(&currentTime);
        
        LARGE_INTEGER elapsedSinceStartTimeINT;
        elapsedSinceStartTimeINT.QuadPart = currentTime.QuadPart - g_TestStartTime.QuadPart;
        double elapsedSinceStartTime = elapsedSinceStartTimeINT.QuadPart / (double)g_lFrequency.QuadPart;

        switch (g_SampleStablizationState)
        {
        case SAMPLE_STABALIZATION_STEP1_RESET:
            {
                g_SampleStablizationState = SAMPLE_STABALIZATION_STEP2_STABALIZE;
                g_AverageFPS.Reset();
            }
            break;
        case SAMPLE_STABALIZATION_STEP2_STABALIZE: 
            if (g_AverageFPS.GetElapsedTime() > 2.f) // wait # seconds to stabilize
            {
                g_SampleStablizationState = SAMPLE_STABALIZATION_STEP3_RECORD;
                g_AverageFPS.Reset();
            }
            break;
        case SAMPLE_STABALIZATION_STEP3_RECORD: 
            if (// g_AverageFPS.GetElapsedFrames() > 100 // wait for # frames
                // ||
                g_AverageFPS.GetElapsedTime() > 5.f) // or # seconds
            {
                g_SampleStablizationState = SAMPLE_STABALIZATION_STEP1_RESET;

                g_fMeasuredFPS = g_AverageFPS.GetAverageFPS();

                int NumberDPs = CalculateDPs( );
                int DPs = max(min(NumberDPs,g_dwMaxNumberofSQRTDPs*g_dwMaxNumberofSQRTDPs),g_dwMinNumberofSQRTDPs*g_dwMinNumberofSQRTDPs);

                int currentThreads = g_bMultiThread ? max(min(g_dwNumberofRecordThreads,g_dwMaxNumberofRecordThreads),g_dwMinNumberofRecordThreads) : 0;
                OutputData(g_pOutputFile,
                    max(min(g_dwCPULoops,g_dwMaxNumberofCPULoops),g_dwMinNumberofCPULoops),
                    DPs,
                    currentThreads,
                    g_fMeasuredTotalCPULoadPerDraw,
                    g_fArtificialCPULoadPerFrame,
                    g_fMeasuredFPS,
                    1.f/g_fMeasuredFPS);
                g_TestLoops += g_TestLoopsIncrement;
                if(g_TestLoops > g_TestEndLoops)
                {
                    g_TestLoops = g_TestStartLoops;

                    // We are incrementing the goal DPs, but in reality use the square root
                    // Keep incrementing until we get to the next unique square root value.
                    int lastSqrtDP = (int)(sqrt(float(g_TestDPs)));
                    do 
                    {
                        g_TestDPs += g_TestDPsIncrement;
                    }
                    while (lastSqrtDP == (int)(sqrt(float(g_TestDPs))));

                    if(g_TestDPs > g_TestEndDPs)
                    {
                        g_TestDPs = g_TestStartDPs;
                        g_TestThreads += g_TestThreadsIncrement;
                        if(g_TestThreads > g_TestEndThreads)
                        {
                            if(g_pOutputFile)
                            {
                                fclose(g_pOutputFile);
                            }
                            g_bAutoTesting = false;
                            g_bInAutoTesting = false;
                            g_bSaveSample = false; 
                            g_pOutputFile = NULL;
                            ShowSliders(true);
                            g_HUD.GetButton( IDC_STARTTESTING )->SetText( L"Start Testing");
                        }
                    }
                }
                else if( g_bSaveSample )
                {
                    if(g_pOutputFile)
                    {
                        fclose(g_pOutputFile);
                    }
                    g_bAutoTesting = false;
                    g_bInAutoTesting = false;
                    g_bSaveSample = false; 
                    g_pOutputFile = NULL;
                    ShowSliders(true);
                    g_HUD.GetButton( IDC_STARTTESTING )->SetText( L"Start Testing");
                    return;
                }
    #if 0
                char temp[300];
                sprintf_s(temp,299,"loop %d,DPs %d,Threads %d\n",g_TestLoops,g_TestDPs,g_TestThreads);
                OutputDebugStringA(temp);
    #endif
                if(g_bAutoTesting && g_bInAutoTesting && g_pOutputFile)
                    SetState(g_TestLoops,g_TestDPs,g_TestThreads);
            }
            break;
        default:
               assert(!"Invalid g_SampleStablizationState");
        }
    }
    else if(g_bAutoTesting && g_bInAutoTesting && g_pOutputFile==NULL)
    {
        g_bSaveSample = false; 
        g_bAutoTesting = false; 
        g_bInAutoTesting = false;
        g_pOutputFile = NULL;
        g_HUD.GetButton( IDC_STARTTESTING )->SetText( L"Start Testing");
    }
}
